import type { Notice } from '@/types/notice'
import type { NoticeController } from './definition'
import { throttle } from 'lodash'
import {
  DOOR_STATE_OPEN,
  LOCAL_CONTROL_ACTIVE,
  REMOTE_CONTROL_ACTIVE,
  REMOTE_CONTROL_START_ALLOWED,
  DOOR_STATE,
  DOOR_STATES,
} from '@/constants/Command'
import { acknowledgeEvent, getActionHandlerInfo, rejectEvent } from '@/api/event'
import type { BaseController } from '@/controller/BaseAppliance/definition'
import { useControlState } from '@/controller/BaseAppliance/useControl'
import { RemoteTypes } from '@/controller/base/remote'
import { NoticeAdded, NoticeRemoved } from '@/constants/UniEventKeys'
import { TrackType, trackEvent } from '@/dataReport/tracks'
import { safeTrack } from '@/dataReport/dataReportUtil'
import { nextTickPromise } from '@/utils/mpHelper'

type StateValue = string | number | boolean | null
type FetchAction = { msg: NoticeQuery<StateValue>; callback: (notice: Notice | null) => any }
const awaitFetchActions: FetchAction[] = [] // 查询队列

const DISCONNECTED = 'DISCONNECTED'
/**
 * 通知冲突Key查询
 */
const ConflictKeys = [
  // 家电离线
  DISCONNECTED,
  // 本地操作
  LOCAL_CONTROL_ACTIVE,
  // 远程控制
  REMOTE_CONTROL_ACTIVE,
  // 远程启动
  REMOTE_CONTROL_START_ALLOWED,
]

export const createNoticeState: () => NoticeController.PureState = () => ({
  // 顶部通知列表
  rawNoticeList: [],
})

export const NoticeGetters: NoticeController.Getters = {
  noticeList() {
    // 处理后的通知列表
    const noticeList: Notice[] = []

    // 可能冲突的Key
    const hasConflictKeys = new Set<string>()

    // 处理ActionHandler配置列表
    this.rawNoticeList.forEach((notice) => {
      // 记录可能冲突的Key
      if (ConflictKeys.includes(notice.key)) {
        hasConflictKeys.add(notice.key)
      }

      // 过滤不需要显示的ActionHandler
      if (notice.triggerActionImmediate !== true) {
        noticeList.push(notice)
      }
    })

    if (!hasConflictKeys.size) return noticeList

    // 离线状态下，其他通知都不显示
    if (hasConflictKeys.has(DISCONNECTED)) {
      return noticeList.filter((notice) => notice.key === DISCONNECTED)
    }

    // 记录需要过滤的Key
    const needFilterKeys = new Set()

    // 存在本地操作时 过滤远程控制
    if (hasConflictKeys.has(LOCAL_CONTROL_ACTIVE)) {
      needFilterKeys.add(REMOTE_CONTROL_ACTIVE)
    }
    // 不在本地操作 且存在远程控制时 过滤远程启动
    else if (hasConflictKeys.has(REMOTE_CONTROL_ACTIVE)) {
      needFilterKeys.add(REMOTE_CONTROL_START_ALLOWED)
    }

    // 过滤数据
    return noticeList.filter((notice) => !needFilterKeys.has(notice.key))
  },
  /**
   * 排除特定的key，比如：家电状态、程序切换、option切换
   */
  ignoredNoticeQueryKeys() {
    return ['OperationState', 'Option', 'Selected'].concat(this.customIgnoredNoticeQueryKeys)
  },
  customIgnoredNoticeQueryKeys() {
    return []
  },
}

export const NoticeActions: NoticeController.Actions = {
  addNotice(notice) {
    // 判断是否存在相同Key 存在则删除之前的消息
    const existIndex = this.rawNoticeList.findIndex((item) => item.key === notice.key)
    if (existIndex !== -1) {
      this.rawNoticeList.splice(existIndex, 1)
    }

    // 添加最新数据
    const newNoticeList = [notice, ...this.rawNoticeList].sort(
      (previous, forward) => previous.ranking - forward.ranking
    )
    this.rawNoticeList = newNoticeList

    // 触发Action已添加通知
    uni.$emit(NoticeAdded, notice)
  },
  removeNotice(notice, isSameValue) {
    const noticeKey = notice.key
    this.rawNoticeList = this.rawNoticeList.filter(
      (item) => item.key !== noticeKey || (isSameValue && item.key === noticeKey && item.value === notice.value)
    )

    // 触发Action已移除通知
    uni.$emit(NoticeRemoved, notice)
  },
  /**
   * 确认继续执行事件
   */
  async acknowledgeNoticeEvent(notice) {
    let res: any = null
    try {
      res = await acknowledgeEvent(this._datasource.haId, notice.key)
    } catch (error) {
      res = error
    } finally {
      safeTrack(() => {
        trackEvent(
          'ha_event_acknowledge',
          { notice, successOrNot: res.code == 0, error_code: res.code, response_msg: res.msg },
          TrackType.ApplianceDetail
        )
      })
    }
  },
  /**
   * 拒绝执行该事件
   */
  async rejectNoticeEvent(notice) {
    let res: any = null
    try {
      res = await rejectEvent(this._datasource.haId, notice.key)
    } catch (error) {
      res = error
    } finally {
      safeTrack(() => {
        trackEvent(
          'ha_event_reject',
          { notice, successOrNot: res.code == 0, error_code: res.code, response_msg: res.msg },
          TrackType.ApplianceDetail
        )
      })
    }
  },

  getCustomNotice() {
    return void 0
  },
}

export function useNoticeEffects<Control extends BaseController.Control>(
  control: Control,
  options: BaseController.ConstructorOptions
) {
  // 仅在inhouse家电的详情页查询events (oem家电不支持events接口)
  if (options.remoteType === RemoteTypes.Inhouse) {
    control.worker.onLoad(() => {
      return control.remote.loadAllEvents()
    })
  }
  control.remote.addBatchObserve({
    // inhouse家电监听status变更
    acceptTriggerByStatus: options.remoteType === RemoteTypes.Inhouse,
    // oem家电监听setting变更
    acceptTriggerBySetting: options.remoteType === RemoteTypes.Oem,
    matcher: (msg) => {
      // 默认的通知处理方法，排除部分会频繁触发，且不需要调用的

      return (
        control.store.ignoredNoticeQueryKeys.every((fragment) => !msg.key.includes(fragment)) &&
        ['string', 'number', 'boolean'].includes(typeof msg.value)
      )
    },
    async handler(msg) {
      // 获取接口返回的通知配置
      const notice = await getNoticeAction(msg)
      if (notice) {
        // 添加数据
        this.store.addNotice(notice)
      } else {
        this.store.removeNotice(
          {
            key: msg.key,
            value: msg.value,
          },
          true
        )
      }
    },
  })

  const controlState = useControlState(control)

  // 离线提示
  syncState(() => controlState.isOffline.value, OfflineNotice)

  /**
   * 同步事件状态
   * @param stateTrigger 状态监听触发器
   * @param noticeArgs 匹配状态参数
   */
  async function syncState<T extends StateValue = boolean>(stateTrigger: () => T, noticeArgs: NoticeQuery<T>) {
    watch(stateTrigger, async (value) => {
      // 监听值与实际值不相同时 只移除通知
      if (noticeArgs.value !== value) {
        control.store.removeNotice(noticeArgs, false)
        return
      }

      const notice = await getNoticeAction({ key: noticeArgs.key, value })
      notice ? control.store.addNotice(notice) : control.store.removeNotice(noticeArgs, false)
    })
  }

  /**
   * 获取接口配置的通知
   * @param msg websocket消息体
   * @returns 消息处理内容
   */
  async function getNoticeAction<T extends StateValue = boolean>(msg: NoticeQuery<T>): Promise<Notice | null> {
    /**
     * 临时适配HA Event配置
     */
    try {
      const customNotice = control.store.getCustomNotice(msg as NoticeQuery<string | number | boolean>)
      if (customNotice !== void 0) {
        return Promise.resolve(customNotice)
      }
    } catch (e) {
      console.error(e)
    }

    return new Promise(async (resolve, reject) => {
      awaitFetchActions.push({ msg, callback: (notice: Notice | null) => resolve(notice) })

      try {
        await nextTickPromise()
        await throttleNoticeActionGetter()
      } catch (e) {
        console.error(e)
        reject(e)
      }
    })
  }

  const throttleNoticeActionGetter = throttle(async () => {
    if (!awaitFetchActions.length) return

    /**
     * 去重 获取数据
     */
    const reducedMap = awaitFetchActions.reduce<Map<string, FetchAction>>((reducedMap, action) => {
      // 过滤数组类型
      if (!Array.isArray(action.msg.value)) {
        reducedMap.set(action.msg.key, action)
      }
      return reducedMap
    }, new Map())
    const fetchActions = [...reducedMap.values()]
    const fetchMessages = fetchActions.map((action) => action.msg)

    // 清空本次查询队列
    awaitFetchActions.splice(0)

    const actions = await getNoticeActions(fetchMessages)
    actions?.forEach((action, actionIndex) => {
      fetchActions[actionIndex].callback(action || null)
    })
  }, 1000)

  async function getNoticeActions(msgQueue: NoticeQuery<StateValue>[]) {
    const { brand, type, vib } = control.store._datasource
    const payload = msgQueue.map(({ key, value }) => ({ key, value, brand, type, vib }))
    const res = await getActionHandlerInfo(payload)
    return res.data
  }
}

export type NoticeQuery<T extends string | number | boolean | null = boolean> = { key: string; value: T }
// 离线提示
export const OfflineNotice: NoticeQuery = {
  key: 'DISCONNECTED',
  value: true,
}
// 远程控制提示
export const RemoteControlNotice: NoticeQuery = {
  key: REMOTE_CONTROL_ACTIVE,
  value: false,
}
// 远程启动提示
export const RemoteStartNotice: NoticeQuery = {
  key: REMOTE_CONTROL_START_ALLOWED,
  value: false,
}
// 本地控制提示
export const LocalControlNotice: NoticeQuery = {
  key: LOCAL_CONTROL_ACTIVE,
  value: true,
}
// 门未关提示
export const DoorOpenedNotice: NoticeQuery<DOOR_STATES> = {
  key: DOOR_STATE,
  value: DOOR_STATE_OPEN,
}
